package cz.acies.uniql.sql.element;

import java.util.*;

import org.dom4j.Element;
import org.dom4j.dom.DOMElement;


import cz.acies.uniql.dialect.Dialect;
import cz.acies.uniql.sql.UniQLExpr;

public class UniQLHaving extends UniQLExpr 
{
	private static final long serialVersionUID = -3086834397944673L;
	
	private UniQLCriterion criterions;

	/**
	 * Konstruktor tridy UniQLHaving.
	 */
	public UniQLHaving() {
		super();
	}

	/**
	 * Konstruktor tridy UniQLHaving.
	 * 
	 * @param dialect - dialect
	 */
	public UniQLHaving(Dialect dialect) {
		super(dialect);
	}
	
	/**
	 * Konstruktor vytvori nonou instanci objektu UniQLHaving s vlastnostmi
	 * objektu zadaneho jako parametr konstruktoru.
	 *  
	 * @param orderBy
	 */
	public UniQLHaving(UniQLHaving expr) throws Exception {
		this();
		UniQLHaving clone = (UniQLHaving) expr.clone();
		
		setId(clone.getId());
		setName(clone.getName());
		setDialect(clone.getDialect());
		setAliasMap(clone.getAliasMap());
		
		setCriterions((clone.getCriterions() != null) ? clone.getCriterions() : null);
	}

	// -----  ------------------  ---------------------------------------------	
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#translate()
	 */
	public String translate() throws Exception {
		//String s = new String("HAVING ");
		StringBuffer sb = new StringBuffer();
		if (criterions != null && !criterions.isEmpty()) {
			sb.append("HAVING ");
			criterions.setUniQLProperties(this);
			sb.append(criterions.translate());
		}
		return sb.toString();
	}
	
	// ----- Getter & Setter --------------------------------------------------
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#clear()
	 */
	public UniQLHaving clear() {
		if (criterions != null) criterions.clear();
		criterions = null;
		return this;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#clone()
	 */
	@Override
	public Object clone() throws CloneNotSupportedException {
		Object clone = super.clone();
		assert clone instanceof UniQLHaving;
		((UniQLHaving) clone).setCriterions((criterions != null) ? (UniQLCriterion)criterions.clone() : null);
		return clone;
	}

	// -----  ------------------  ---------------------------------------------
	
	/**
	 * Prida novy objekt condition. U teto metody je mezi pridavany condition a 
	 * pripadny dalsi pridavany condition, automaticky dolnen operator AND.   
	 * 
	 * @param cf - cf
	 * 
	 * @return vraci having
	 */
	public UniQLHaving addCondition(UniQLCondition cf) {
		if (this.criterions == null) this.criterions = new UniQLCriterion();
		this.criterions.addCondition(cf);
		return this;
	}
		
	/**
	 * Prida novy objekt condition a oprerator, ktery bude ve vyslednem dotazu za
	 * pridavanou podminkou.
	 * 
	 * @param cf - cf
	 * @param op - op
	 * 
	 * @return vraci having
	 */
	public UniQLHaving addCondition(UniQLCondition cf, String op) {
		if (this.criterions == null) this.criterions = new UniQLCriterion();
		this.criterions.addCondition(cf, op);
		return this;
	}

	/**
	 * Navraci kontejner criterions. 
	 * 
	 * @return - vraci hodnotu criterions
	 */
	public UniQLCriterion getCriterions() {
		return criterions;
	}

	/**
	 * Nahradi stavajici criterions za novou.
	 * 
	 * @param criterions - novy kontejner criterions 
	 */
	public void setCriterions(UniQLCriterion criterions) {
		this.criterions = criterions;
	}

	/**
	 * P�id� ke stavajicim podm�nk�m nov�, obsa�en� v parametru criterions.
	 * 
	 * @param kontejner criterions obsahuj�c� nov� podm�nky.  
	 */
	public UniQLHaving addCriterions(UniQLCriterion c) {
		return addCriterions(c, null);
	}

	/**
	 * P�id� ke stavajicim podm�nk�m nov�, obsa�en� v parametru criterions. a 
	 * nastav� u posledni p�id�van� polo�ky oper�tor na hodnotu parametru op.
	 * 
	 * @param kontejner criterions obsahuj�c� nov� podm�nky.  
	 */
	public UniQLHaving addCriterions(UniQLCriterion c, String op) {
		if (c == null) return this;
		try {
			this.criterions.addCriterions(c);
			if (op != null) this.criterions.setLastConditionOperator(op);			
		} catch (Exception exc) {
			exc.printStackTrace();
		}
		return this;
	}

	/**
	 * P�id� ke stavajicim podm�nk�m nov�, obsa�en� v parametru criterions. a 
	 * nastav� posledni polo�ky st�vaj�c�ho kontejneru criterions oper�tor na 
	 * hodnotu parametru op.
	 * 
	 * @param kontejner criterions obsahuj�c� nov� podm�nky.  
	 */
	public UniQLHaving addCriterions(String op, UniQLCriterion c) {
		if (op != null) this.criterions.setLastConditionOperator(op);
		return addCriterions(c);
	}
	
	// -----  -----------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#transToXML()
	 */
	public String transToXML() throws Exception {
		DOMElement node = new DOMElement("UniQLHaving");
		transToXML(node);
		return node.asXML();
	}
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#transToXML(org.dom4j.dom.DOMElement)
	 */
	public DOMElement transToXML(DOMElement node) throws Exception {
		node.setName("UniQLHaving");
		if (criterions != null) {
			DOMElement childs = criterions.transToXML(new DOMElement("UniQLExpr"));
			node.appendChild(childs);
		}
		return node;
	}
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#xmlToExpr(java.lang.String)
	 */
	public UniQLExpr xmlToExpr(String xml) throws Exception {
		System.out.println("UniQLHaving.xmlToExpr(xml)");
		return null;
	}

	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#xmlToExpr(org.dom4j.Element)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public UniQLExpr xmlToExpr(Element node) throws Exception {
		ArrayList<Element> params = new ArrayList<Element>(node.elements());
		for (int i = 0; i < params.size(); i++) {
			Element child = (Element)params.get(i);
			String nodename = child.getName();
			UniQLExpr expr = null;
			if (nodename.trim().equals("UniQLCriterion")) {
				expr = new UniQLCriterion();
				expr.xmlToExpr(child);
				if (expr != null) {
					this.setCriterions((UniQLCriterion)expr);
				}				
			}
		}
		return this;
	}
}
